﻿using System.Buffers;
using Common.dto;
using Common.Shared.resp;
using JWT;
using JWT.Exceptions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Primitives;
using WebApi.utils;

namespace WebApi.filter;

public class AuthorizationFilter : IAuthorizationFilter
{
    /**
     * jwt 参考
     * https://github.com/jwt-dotnet/jwt
     */
    public void OnAuthorization(AuthorizationFilterContext context)
    {
        if (context.HttpContext.Request.Path.ToString().StartsWith("/api/Login"))
        {
            return;
        }

        if (context.HttpContext.Request.Headers.TryGetValue("Authorization", out StringValues Authorizations))
        {
            try
            {
                foreach (string? token in Authorizations)
                {
                    if (token is null)
                    {
                        continue;
                    }

                    IDictionary<string, object> decodeToObject =
                        TokenUtils.Decoder.DecodeToObject<IDictionary<string, object>>(new JwtParts(token), true);

                    UserDto userDto = new UserDto();


                    if (decodeToObject.TryGetValue("userId", out object userId))
                    {
                        userDto.Id = int.Parse(userId.ToString());
                    }

                    if (decodeToObject.TryGetValue("userName", out object userName))
                    {
                        userDto.Name = userName.ToString();
                    }

                    if (decodeToObject.TryGetValue("userAccount", out object userAccount))
                    {
                        userDto.Account = userAccount.ToString();
                    }

                    SecurityContextHolder.Set(userDto);

                    return;
                }
            }
            catch (TokenNotYetValidException)
            {
                Console.WriteLine("Token is not valid yet");
                context.Result = new JsonResult(Resp<object>.Fail(401, "无效令牌"));
                return;
            }
            catch (TokenExpiredException)
            {
                Console.WriteLine("Token has expired");
                context.Result = new JsonResult(Resp<object>.Fail(402, "令牌已过期"));
                return;
            }
            catch (SignatureVerificationException)
            {
                Console.WriteLine("Token has invalid signature");
                context.Result = new JsonResult(Resp<object>.Fail(403, "令牌签名无效"));
                return;
            }
        }

        context.HttpContext.Response.WriteAsJsonAsync(Resp<object>.Fail("令牌已过期"));

        context.Result = new JsonResult(Resp<object>.Fail(404, "请求头中未包含令牌"));
    }
}